package com.seadragon.app.ksr.util;

import static com.seadragon.app.ksr.model.KsrConstants.PROPERTIES;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

import java.util.Iterator;
import java.util.List;

import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.seadragon.app.ksr.model.Address;
import com.seadragon.app.ksr.model.Business;
import com.seadragon.app.ksr.model.Category;
import com.seadragon.app.ksr.model.Customer;
import com.seadragon.app.ksr.model.Office;
import com.seadragon.app.ksr.model.Review;
import com.seadragon.app.ksr.model.tiger.County;
import com.seadragon.app.ksr.model.tiger.Place;
import com.seadragon.app.ksr.model.tiger.State;
import com.seadragon.app.ksr.model.tiger.Zip;
import com.seadragon.app.ksr.service.BusinessService;
import com.seadragon.app.ksr.service.CustomerService;
import com.seadragon.app.ksr.service.OfficeService;
import com.seadragon.app.ksr.service.ReviewService;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Polygon;

@Component("indexManager")
public class IndexManagerESJavaImpl implements IndexManager {
	private static final int PAGE_SIZE = 100;
	private static Logger logger = LoggerFactory.getLogger(IndexManagerESJavaImpl.class);
	@Autowired
	private Client client;

	@Autowired
	private OfficeService officeService;

	@Autowired
	private CustomerService customerService;

	@Autowired
	private BusinessService businessService;

	@Autowired
	private ReviewService reviewService;

	public IndexRequestBuilder createIndexRequestBuilder(Office office) throws Exception{
		IndexRequestBuilder irb = client.prepareIndex(indexName(), "office", Long.toString(office.getId()));
		Address addr = office.getAddress();
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("id", office.getId())
					.field("description", office.getDescription())
					.field("specialty", office.getSpecialty())
					.field("emailAddress", office.getEmailAddress())
					.field("phoneNumber", office.getPhoneNumber())
					.field("priceRange", office.getPriceRange())
					.field("rating", office.getRating())
					.field("reviewCount", office.getReviewCount())
					.field("price", office.getPrice())
					.startObject("address")
						.field("id", addr.getId())
						.field("addressLine1", addr.getAddressLine1())
						.field("addressLine2", addr.getAddressLine2())
						.field("city", addr.getCity())
						.field("state", addr.getState())
						.field("zip", addr.getZip())
						.field("streetNumber", addr.getStreetNumber())
						.startObject("location")
							.field("lat", addr.getLatitude())
							.field("lon", addr.getLongitude())
						.endObject()
						.field("streetName", addr.getStreetName())
						.field("streetType", addr.getStreetType())
						.field("geocodedCity", addr.getGeocodedCity())
						.field("geocodedCounty", addr.getGeocodedCounty())
						.field("geocodedState", addr.getGeocodedState())
						.field("geocodedZip", addr.getGeocodedZip())
					.endObject();
		xb.startObject("business")
		.field("id", office.getBusiness().getId())
		.field("businessName", office.getBusiness().getBusinessName())
		.field("description", office.getBusiness().getDescription())
		.field("specialty", office.getBusiness().getSpecialty());

		xb.startArray("categories");
		for(Category category : office.getBusiness().getCategories()){
			xb.startObject()
				.field("id", category.getId())
				.field("name", category.getName())
			.endObject();
		}
		xb.endArray().endObject().endObject();
		irb.setSource(xb);
		return irb;
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Office)
	 */
	@Override
	public void insertDocument(Office office) throws Exception{
		IndexRequestBuilder irb = createIndexRequestBuilder(office);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkOfficeDocuments(java.util.List)
	 */
	@Override
	public void insertBulkOfficeDocuments(List<Office> officeList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(Office office : officeList){
			bulkRequest.add(createIndexRequestBuilder(office));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(Business business) throws Exception{
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("id", business.getId())
					.field("businessName", business.getBusinessName())
					.field("description", business.getDescription())
					.field("specialty", business.getSpecialty());
		
		xb.startArray("categories");
		for(Category category : business.getCategories()){
			xb.startObject()
				.field("id", category.getId())
				.field("name", category.getName())
			.endObject();
		}
		xb.endArray();
		xb.endObject();
		return client.prepareIndex(indexName(), "business", Long.toString(business.getId())).setSource(xb);
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Business)
	 */
	@Override
	public void insertDocument(Business business) throws Exception{
		IndexRequestBuilder irb= createIndexRequestBuilder(business);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkBusinessDocuments(java.util.List)
	 */
	@Override
	public void insertBulkBusinessDocuments(List<Business> businessList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(Business business : businessList){
			bulkRequest.add(createIndexRequestBuilder(business));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(Customer customer) throws Exception{
		Address ra = customer.getResidentAddress();
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("id", customer.getId())
					.field("firstName", customer.getFirstName())
					.field("lastName", customer.getLastName())
					.field("interest", customer.getInterest())
					.field("dateOfBirth", customer.getDateOfBirth())
					.startObject("address")
						.field("id", ra.getId())
						.field("addressLine1", ra.getAddressLine1())
						.field("addressLine2", ra.getAddressLine2())
						.field("city", ra.getCity())
						.field("state", ra.getState())
						.field("zip", ra.getZip())
						.field("streetNumber", ra.getStreetNumber())
						.startObject("location")
							.field("lat", ra.getLatitude())
							.field("lon", ra.getLongitude())
						.endObject()
						.field("streetName", ra.getStreetName())
						.field("streetType", ra.getStreetType())
						.field("geocodedCity", ra.getGeocodedCity())
						.field("geocodedCounty", ra.getGeocodedCounty())
						.field("geocodedState", ra.getGeocodedState())
						.field("geocodedZip", ra.getGeocodedZip())
					.endObject()
				.endObject();
		return client.prepareIndex(indexName(), "customer", Long.toString(customer.getId())).setSource(xb);

	}
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Customer)
	 */
	@Override
	public void insertDocument(Customer customer) throws Exception {
		IndexRequestBuilder irb = createIndexRequestBuilder(customer);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkCustomerDocuments(java.util.List)
	 */
	@Override
	public void insertBulkCustomerDocuments(List<Customer> customerList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(Customer customer : customerList){
			bulkRequest.add(createIndexRequestBuilder(customer));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(Review review) throws Exception{
		Customer customer = review.getCustomer();
		Address ra = customer.getResidentAddress();
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("id", review.getId())
					.field("title", review.getTitle())
					.field("content", review.getContent())
					.field("dateCreated", review.getDateCreated())
					.startObject("customer")
						.field("firstName", review.getCustomer().getFirstName())
						.field("lastName", review.getCustomer().getLastName())
						.field("interest", customer.getInterest())
						.field("dateOfBirth", customer.getDateOfBirth())
						.startObject("address")
							.field("id", ra.getId())
							.field("addressLine1", ra.getAddressLine1())
							.field("addressLine2", ra.getAddressLine2())
							.field("city", ra.getCity())
							.field("state", ra.getState())
							.field("zip", ra.getZip())
							.field("streetNumber", ra.getStreetNumber())
							.startObject("location")
								.field("lat", ra.getLatitude())
								.field("lon", ra.getLongitude())
							.endObject()
							.field("streetName", ra.getStreetName())
							.field("streetType", ra.getStreetType())
							.field("geocodedCity", ra.getGeocodedCity())
							.field("geocodedCounty", ra.getGeocodedCounty())
							.field("geocodedState", ra.getGeocodedState())
							.field("geocodedZip", ra.getGeocodedZip())
						.endObject()
					.endObject()
				.endObject();
		IndexRequestBuilder irb = client.prepareIndex(indexName(), "review", Long.toString(review.getId()));
		irb.setParent(Long.toString(review.getOffice().getId()));
		irb.setSource(xb);
		return irb;
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Review)
	 */
	@Override
	public void insertDocument(Review review) throws Exception{
		IndexRequestBuilder irb = createIndexRequestBuilder(review);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkReviewDocuments(java.util.List)
	 */
	@Override
	public void insertBulkReviewDocuments(List<Review> reviewList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(Review review: reviewList){
			bulkRequest.add(createIndexRequestBuilder(review));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(State state) throws Exception{
		logger.info("State: " + state.getStusps());
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("geoid", state.getGeoid())
					.field("stusps", state.getStusps())
					.field("name", state.getName())
					.startObject("geom")
						.field("type", "multipolygon")
		.startArray("coordinates").startArray();
						for(int i = 0; i < state.getGeom().getNumGeometries();i++){
							xb.startArray();
							Polygon polygon = (Polygon)state.getGeom().getGeometryN(i);
							LineString shell = polygon.getExteriorRing();
							
							for(Coordinate coordinate : shell.getCoordinates()){
								xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//								logger.info("Shell: " + coordinate.x + ", " + coordinate.y);
							}
							for(int k = 0; k < polygon.getNumInteriorRing(); k++){
								LineString hole = polygon.getInteriorRingN(k);
								xb.startArray();
								for(Coordinate coordinate : hole.getCoordinates()){
									xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//									logger.info("Hole: " + coordinate.x + ", " + coordinate.y);
								}
								xb.endArray();
							}
							xb.endArray();
						}
						xb.endArray().endArray()
					.endObject()
				.endObject();
		IndexRequestBuilder irb = client.prepareIndex(tigerIndexName(), "state", state.getGeoid());
		irb.setSource(xb);
		return irb;
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Review)
	 */
	@Override
	public void insertDocument(State state) throws Exception{
		IndexRequestBuilder irb = createIndexRequestBuilder(state);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkReviewDocuments(java.util.List)
	 */
	@Override
	public void insertBulkStateDocuments(List<State> stateList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(State state: stateList){
			bulkRequest.add(createIndexRequestBuilder(state));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(County county) throws Exception{
		logger.info("County: " + county.getName());
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("geoid", county.getGeoid())
					.field("countyfp", county.getCountyfp())
					.field("state", county.getState())
					.field("name", county.getName())
					.startObject("geom")
						.field("type", "multipolygon")
		.startArray("coordinates").startArray();
						for(int i = 0; i < county.getGeom().getNumGeometries();i++){
							xb.startArray();
							Polygon polygon = (Polygon)county.getGeom().getGeometryN(i);
							LineString shell = polygon.getExteriorRing();
							
							for(Coordinate coordinate : shell.getCoordinates()){
								xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//								logger.info("Shell: " + coordinate.x + ", " + coordinate.y);
							}
							for(int k = 0; k < polygon.getNumInteriorRing(); k++){
								LineString hole = polygon.getInteriorRingN(k);
								xb.startArray();
								for(Coordinate coordinate : hole.getCoordinates()){
									xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//									logger.info("Hole: " + coordinate.x + ", " + coordinate.y);
								}
								xb.endArray();
							}
							xb.endArray();
						}
						xb.endArray().endArray()
					.endObject()
				.endObject();
		IndexRequestBuilder irb = client.prepareIndex(tigerIndexName(), "county", county.getGeoid());
		irb.setSource(xb);
		return irb;
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Review)
	 */
	@Override
	public void insertDocument(County county) throws Exception{
		IndexRequestBuilder irb = createIndexRequestBuilder(county);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkReviewDocuments(java.util.List)
	 */
	@Override
	public void insertBulkCountyDocuments(List<County> countyList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(County county: countyList){
			bulkRequest.add(createIndexRequestBuilder(county));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(Place place) throws Exception{
		logger.info("Place: " + place.getName());
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("geoid", place.getGeoid())
					.field("state", place.getState())
					.field("county", place.getCounty())
					.field("name", place.getName())
//					.startObject("location")
//						.field("lat", place.getLatitude())
//						.field("lon", place.getLongitude())
//					.endObject()

					.startObject("geom")
						.field("type", "multipolygon")
		.startArray("coordinates").startArray();
						for(int i = 0; i < place.getGeom().getNumGeometries();i++){
							xb.startArray();
							Polygon polygon = (Polygon)place.getGeom().getGeometryN(i);
							LineString shell = polygon.getExteriorRing();
							
							for(Coordinate coordinate : shell.getCoordinates()){
								xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//								logger.info("Shell: " + coordinate.x + ", " + coordinate.y);
							}
							for(int k = 0; k < polygon.getNumInteriorRing(); k++){
								LineString hole = polygon.getInteriorRingN(k);
								xb.startArray();
								for(Coordinate coordinate : hole.getCoordinates()){
									xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//									logger.info("Hole: " + coordinate.x + ", " + coordinate.y);
								}
								xb.endArray();
							}
							xb.endArray();
						}
						xb.endArray().endArray()
					.endObject()
				.endObject();
		IndexRequestBuilder irb = client.prepareIndex(tigerIndexName(), "place", place.getGeoid());
		irb.setSource(xb);
		return irb;
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Review)
	 */
	@Override
	public void insertDocument(Place place) throws Exception{
		IndexRequestBuilder irb = createIndexRequestBuilder(place);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkReviewDocuments(java.util.List)
	 */
	@Override
	public void insertBulkPlaceDocuments(List<Place> placeList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(Place place :placeList){
			bulkRequest.add(createIndexRequestBuilder(place));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}
	
	public IndexRequestBuilder createIndexRequestBuilder(Zip zip) throws Exception{
		logger.info("Zip: " + zip.getName());
		XContentBuilder xb = jsonBuilder()
				.startObject()
					.field("geoid", zip.getGeoid())
					.field("state", zip.getState())
					.field("county", zip.getCounty())
					.startObject("geom")
						.field("type", "multipolygon")
		.startArray("coordinates").startArray();
						for(int i = 0; i < zip.getGeom().getNumGeometries();i++){
							xb.startArray();
							Polygon polygon = (Polygon)zip.getGeom().getGeometryN(i);
							LineString shell = polygon.getExteriorRing();
							
							for(Coordinate coordinate : shell.getCoordinates()){
								xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//								logger.info("Shell: " + coordinate.x + ", " + coordinate.y);
							}
							for(int k = 0; k < polygon.getNumInteriorRing(); k++){
								LineString hole = polygon.getInteriorRingN(k);
								xb.startArray();
								for(Coordinate coordinate : hole.getCoordinates()){
									xb.startArray().value(coordinate.x).value(coordinate.y).endArray();
//									logger.info("Hole: " + coordinate.x + ", " + coordinate.y);
								}
								xb.endArray();
							}
							xb.endArray();
						}
						xb.endArray().endArray()
					.endObject()
				.endObject();
		IndexRequestBuilder irb = client.prepareIndex(tigerIndexName(), "zip", zip.getGeoid());
		irb.setSource(xb);
		return irb;
	}
	
	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertDocument(com.seadragon.app.ksr.model.Review)
	 */
	@Override
	public void insertDocument(Zip zip) throws Exception{
		IndexRequestBuilder irb = createIndexRequestBuilder(zip);
		IndexResponse response = irb.execute().actionGet();
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#insertBulkReviewDocuments(java.util.List)
	 */
	@Override
	public void insertBulkZipDocuments(List<Zip> zipList) throws Exception {
		BulkRequestBuilder bulkRequest = client.prepareBulk();
		for(Zip zip : zipList){
			bulkRequest.add(createIndexRequestBuilder(zip));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Iterator<BulkItemResponse> iter = bulkResponse.iterator();
			while(iter.hasNext()){
				BulkItemResponse bir = iter.next();
				if(bir.isFailed()){
					logger.error(bir.toString());
				}
			}
		}
	}

	public void searchDocument(){
		GetResponse response = client.prepareGet("library", "book", "2").execute().actionGet();
		
		System.out.println("It's working: " + response.getSourceAsString());
	}
	
	public void deleteDocument(){
		DeleteResponse response = client.prepareDelete("library", "book", "2").execute().actionGet();

	}

	/*
	 * {
	 * 		"mappings":{
	 * 			"office":{
	 * 				"_parent":{
	 * 					"type":"business"
	 * 				},
	 * 				"properties":{
	 * 					"description" : {"type":"string"},
	 * 					"specialty" : {"type":"string","analyzer":"english"},
	 * 					"priceRange" : {"type":"short"},
	 * 					"rating":{"type":"short"},
	 * 					"price":{"type": "short"},
	 * 					"address" :{
	 * 						"properties":{
	 * 							"id":{"type":"long"},
	 * 							"streetNumber":{"type" :"string","index" :"not_analyzed"},
	 * 							"streetName":{"type":"string","index":"not_analyzed"},
	 * 							"streetType" :{"type":"string","index":"not_analyzed"},
	 * 							"streetName":{"type" :"string","index" :"not_analyzed"},
	 * 							"geocodedCity":{"type":"string","index": "not_analyzed"},
	 * 							"geocodedCounty" :{"type":"string","index":"not_analyzed"},
	 * 							"geocodedState":{"type":"string","index":"not_analyzed"},
	 * 							"geocodedZip":{"type" :"string","index":"not_analyzed"}
	 * 						}
	 * 					}
	 * 				}
	 * 			}
	 * 		}
	 * }
	 */
	public XContentBuilder buildOfficeMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("office")
						.startObject(PROPERTIES)
							.startObject("id")
								.field("type", "long")
							.endObject()
							.startObject("description")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("specialty")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("phoneNumber")
								.field("type", "string")
								.field("index", "no")
								.field("store", "yes")
							.endObject()
							.startObject("eamilAddress")
								.field("type", "string")
								.field("index", "no")
								.field("store", "yes")
							.endObject()
							.startObject("priceRange")
								.field("type", "short")
							.endObject()
							.startObject("reviewCount")
								.field("type", "integer")
							.endObject()
							.startObject("rating")
								.field("type", "short")
							.endObject()
							.startObject("price")
								.field("type", "short")
							.endObject()
							.startObject("business")
								.startObject(PROPERTIES)
									.startObject("id")
										.field("type", "long")
									.endObject()
									.startObject("businessName")
										.field("type", "string")
									.endObject()
									.startObject("description")
										.field("type", "string")
										.field("analyzer", "english")
									.endObject()
									.startObject("specialty")
										.field("type", "string")
										.field("analyzer", "english")
									.endObject()
									.startObject("categories")
										.field("type", "nested")
									.endObject()
								.endObject()
							.endObject()
							.startObject("address")
								.startObject(PROPERTIES)
									.startObject("id")
										.field("type", "long")
									.endObject()
									.startObject("addressLine1")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("addressLine2")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("city")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("state")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("zip")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("streetNumber")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("location")
										.field("type", "geo_point")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("streetName")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("streetType")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("streetName")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedCity")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedCounty")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedState")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedZip")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
								.endObject()
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		System.out.println(xbMapping.string());
		client.admin().indices().preparePutMapping(indexName())
		.setType("office").setSource(xbMapping).execute().actionGet();
		return xbMapping;
	}

	public XContentBuilder buildBusinessMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("business")
						.startObject(PROPERTIES)
							.startObject("id")
								.field("type", "long")
							.endObject()
							.startObject("businessName")
								.field("type", "string")
							.endObject()
							.startObject("description")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("specialty")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("categories")
								.field("type", "nested")
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(indexName())
		.setType("business").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}

/*	curl -XPUT 'http://localhost:9200/ksr/category/_mapping' -d '
	{
	    "category" : {
	    	"name" : {"type" : "string", "store" : "no"}
	    }
	}
	'
*/
	public XContentBuilder buildCategoryMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("categories")
						.startObject(PROPERTIES)
							.startObject("id")
								.field("type", "long")
							.endObject()
							.startObject("name")
								.field("type", "string")
								.field("index", "not_analyzed")
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(indexName())
		.setType("categories").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}

/*	curl -XPUT 'http://localhost:9200/ksr/review/_mapping' -d '
	{
	    "review" : {
	    	"_parent": { "type" : "office"},
	        "properties" : {
	            "title" : {"type" : "string", "store" : "yes"},
	            "content" : {"type" : "string", "store" : "yes"},
	            "dateCreated" : {"type" : "date", "store" : "no"},
	            "rating" : {"type" : "string", "store" : "yes"}	        }
	    }
	}
	'
*/	public XContentBuilder buildReviewMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("review")
						.startObject("_parent")
							.field("type", "office")
						.endObject()
						.startObject(PROPERTIES)
							.startObject("id")
								.field("type", "long")
							.endObject()
							.startObject("title")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("content")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("dateCreated")
								.field("type", "date")
							.endObject()
							.startObject("rating")
								.field("type", "short")
							.endObject()
							.startObject("customer")
								.startObject(PROPERTIES)
									.startObject("id")
										.field("type", "long")
									.endObject()
									.startObject("firstName")
										.field("type", "string")
									.endObject()
									.startObject("lastName")
										.field("type", "string")
										.field("analyzer", "english")
									.endObject()
									.startObject("interest")
										.field("type", "string")
										.field("analyzer", "english")
									.endObject()
									.startObject("dateOfBirth")
										.field("type", "date")
									.endObject()
									.startObject("address")
										.startObject(PROPERTIES)
											.startObject("id")
												.field("type", "long")
											.endObject()
											.startObject("addressLine1")
												.field("type", "string")
												.field("store", "yes")
												.field("index", "no")
											.endObject()
											.startObject("addressLine2")
												.field("type", "string")
												.field("store", "yes")
												.field("index", "no")
											.endObject()
											.startObject("city")
												.field("type", "string")
												.field("store", "yes")
												.field("index", "no")
											.endObject()
											.startObject("state")
												.field("type", "string")
												.field("store", "yes")
												.field("index", "no")
											.endObject()
											.startObject("zip")
												.field("type", "string")
												.field("store", "yes")
												.field("index", "no")
											.endObject()
											.startObject("streetNumber")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("streetName")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("streetType")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("location")
												.field("type", "geo_point")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("streetName")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("geocodedCity")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("geocodedCounty")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("geocodedState")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
											.startObject("geocodedZip")
												.field("type", "string")
												.field("index", "not_analyzed")
											.endObject()
										.endObject()
									.endObject()
								.endObject()
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(indexName())
		.setType("review").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}

/*	curl -XPUT 'http://localhost:9200/ksr/customer/_mapping' -d '
	{
	    "customer" : {
	        "properties" : {
	            "firstName" : {"type" : "string", "store" : "no"},
	            "lastName" : {"type" : "string", "store" : "no"},
	            "interest" : {"type" : "string", "store" : "yes"},
	            "dateOfBirth" : {"type" : "date", "store" : "no"},
	            "address" : {
	            	"id" : "type" : "string", "store" : "yes"},
	            	"streetNumber" : "type" : "string", "store" : "yes"},
	            	"streetName" : "type" : "string", "store" : "yes"},
	            	"streetType" : "type" : "string", "store" : "yes"},
	            	"geocodeCity" : "type" : "string", "store" : "no"},
	            	"geocodeCounty" : "type" : "string", "store" : "no"},
	            	"geocodeState" : "type" : "string", "store" : "no"},
	            	"geocodeZip" : "type" : "string", "store" : "no"},
	            	"geocodeCity" : "type" : "string", "store" : "no"}
				}
	        }
	    }
	}
	'
*/	public XContentBuilder buildCustomerMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("customer")
						.startObject(PROPERTIES)
							.startObject("id")
								.field("type", "long")
							.endObject()
							.startObject("firstName")
								.field("type", "string")
							.endObject()
							.startObject("lastName")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("interest")
								.field("type", "string")
								.field("analyzer", "english")
							.endObject()
							.startObject("dateOfBirth")
								.field("type", "date")
							.endObject()
							.startObject("address")
								.startObject(PROPERTIES)
									.startObject("id")
										.field("type", "long")
									.endObject()
									.startObject("addressLine1")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("addressLine2")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("city")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("state")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("zip")
										.field("type", "string")
										.field("store", "yes")
										.field("index", "no")
									.endObject()
									.startObject("streetNumber")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("streetName")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("streetType")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("location")
										.field("type", "geo_point")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("streetName")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedCity")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedCounty")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedState")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
									.startObject("geocodedZip")
										.field("type", "string")
										.field("index", "not_analyzed")
									.endObject()
								.endObject()
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(indexName())
		.setType("customer").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}
	
	public String indexName(){
		return "ksr";
	}

	public void createAllMappings() {
		try {
//			buildStateMapping();
//			buildCountyMapping();
//			buildPlaceMapping();
//			buildZipMapping();
//			buildCategoryMapping();
//			buildBusinessMapping();
			buildOfficeMapping();
//			buildCustomerMapping();
//			buildReviewMapping();
		} catch (Exception ex) {
			logger.error(ex.getMessage(), ex);
		}
	}

	/* (non-Javadoc)
	 * @see com.seadragon.app.ksr.util.IndexManager#indexAll()
	 */
	@Override
	@Transactional
	public void indexAll() {
		try {
			int offset = 0;
//			List<Business> businesses = businessService.findAll(offset, PAGE_SIZE);
//			while (businesses != null && businesses.size() > 0) {
//				insertBulkBusinessDocuments(businesses);
//				offset += PAGE_SIZE;
//				businesses = businessService.findAll(offset, PAGE_SIZE);
//			}
//
//			offset = 0;
			List<Office> offices = officeService.findAll(offset, PAGE_SIZE);
			while (offices != null && offices.size() > 0) {
				insertBulkOfficeDocuments(offices);
				offset += PAGE_SIZE;
				offices = officeService.findAll(offset, PAGE_SIZE);
			}

//			offset = 0;
//			List<Customer> customers = customerService.findAll(offset, PAGE_SIZE);
//			while (customers != null && customers.size() > 0) {
//				insertBulkCustomerDocuments(customers);
//				offset += PAGE_SIZE;
//				customers = customerService.findAll(offset, PAGE_SIZE);
//			}
//
//			offset = 0;
//			List<Review> reviews = reviewService.findAll(offset, PAGE_SIZE);
//			while (reviews != null && reviews.size() > 0) {
//				insertBulkReviewDocuments(reviews);
//				offset += PAGE_SIZE;
//				reviews = reviewService.findAll(offset, PAGE_SIZE);
//			}
		} catch (Exception ex) {
			logger.error(ex.getMessage(), ex);
		}
	}
	

	public XContentBuilder buildStateMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("state")
//						.startObject("_source")
//							.field("enabled", "false")
//						.endObject()
						.startObject(PROPERTIES)
							.startObject("geoid")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("stusps")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("name")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("statefp")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("geom")
								.field("type", "geo_shape")
								.field("tree", "quadtree")
								.field("precision", "100m")
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(tigerIndexName())
		.setType("state").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}

	public XContentBuilder buildCountyMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("county")
						.startObject(PROPERTIES)
							.startObject("geoid")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("countyfp")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("name")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("state")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("geom")
								.field("type", "geo_shape")
								.field("tree", "quadtree")
								.field("precision", "100m")
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(tigerIndexName())
		.setType("county").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}

	public XContentBuilder buildPlaceMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("place")
						.startObject(PROPERTIES)
							.startObject("geoid")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("county")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("name")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("state")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
//							.startObject("intpt")
//								.field("type", "geo_point")
//								.field("index", "not_analyzed")
//							.endObject()
							.startObject("geom")
								.field("type", "geo_shape")
								.field("tree", "quadtree")
								.field("precision", "10m")
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(tigerIndexName())
		.setType("place").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}

	public XContentBuilder buildZipMapping() throws Exception {
		XContentBuilder xbMapping = jsonBuilder()
				.startObject()
					.startObject("zip")
						.startObject(PROPERTIES)
							.startObject("geoid")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("county")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
							.startObject("state")
								.field("type", "string")
								.field("store", "yes")
							.endObject()
//							.startObject("intpt")
//								.field("type", "geo_point")
//								.field("index", "not_analyzed")
//							.endObject()
							.startObject("geom")
								.field("type", "geo_shape")
								.field("tree", "quadtree")
								.field("precision", "10m")
							.endObject()
						.endObject()
					.endObject()
				.endObject();
		client.admin().indices().preparePutMapping(tigerIndexName())
		.setType("zip").setSource(xbMapping).execute().actionGet();
		System.out.println(xbMapping.string());
		return xbMapping;
	}
	
	public String tigerIndexName(){
		return "tiger";
	}

	public static void main(String[] argv){
		if(argv == null || argv.length == 0){
			logger.error("Usage: IndexManagerESJavaImpl");
			return;
		}
		ApplicationContext appCtx = new ClassPathXmlApplicationContext("ksr-application-context-sa-postgres.xml");
		IndexManager indexManager = (IndexManager)appCtx.getBean("indexManager");
		for(String s : argv){
			if(s.equalsIgnoreCase("-m")){
				indexManager.createAllMappings();
			}else if(s.equalsIgnoreCase("-i")){
				indexManager.indexAll();
			}
		}
		 ((AbstractApplicationContext)appCtx).close();
	}
}
